package com.nulldev.util.concurrency.threadIt.v4.executors.bqde;

import static com.nulldev.util.concurrency.threadIt.v4.executors.bqde.BQDEUtils.__handle_exception;

import java.util.concurrent.atomic.AtomicBoolean;

import com.nulldev.util.VariableAPI.MathUtil;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ft.FutureTask;

class BQDEThreadLP extends Thread implements ControllableThread {
	private final BQDE instance;
	private final int i;

	public BQDEThreadLP(final BQDE instance, final int i) {
		super(LPThreadGroup.THREAD_GROUP, "BQDEL[i=" + i + "]");
		this.instance = instance;
		this.i = i;
		this.HALT = new AtomicBoolean(this.instance.STOP.get());
	}

	private final AtomicBoolean HALT, BUSY = new AtomicBoolean();

	@Override
	public void run() {
		while (!this.HALT.get()) {
			final Object task;
			try {
				task = this.instance.takeTask(BQDE.BQDE_CONTEXT_TYPE_DEDICATED_LP);
				if (task == null) {
					if (BQDE.ENABLE_THREAD_YIELDING)
						Thread.yield();
					continue;
				}
			} catch (InterruptedException ex) {
				if (BQDE.ENABLE_THREAD_YIELDING)
					Thread.yield();
				continue;
			}
			if (task instanceof BQDETaskChain) {
				final BQDETaskChain tc = (BQDETaskChain) task;
				for (final Runnable chainTask : tc.tasks()) {
					if (chainTask == null)
						continue;
					try {
						this.BUSY.lazySet(true);

						if (chainTask instanceof FutureTask) {
							((FutureTask<?>) chainTask).run(this);
						} else {
							((Runnable) chainTask).run();
						}

						this.BUSY.lazySet(false);
					} catch (Throwable e) {
						this.BUSY.lazySet(false);
						__handle_exception(chainTask, e);
					}
				}
			} else {
				try {
					this.BUSY.lazySet(true);

					if (task instanceof FutureTask) {
						((FutureTask<?>) task).run(this);
					} else {
						((Runnable) task).run();
					}

					this.BUSY.lazySet(false);
				} catch (Throwable e) {
					this.BUSY.lazySet(false);
					__handle_exception(task, e);
				}
			}
			try {
				if (BQDE.ENABLE_THREAD_YIELDING)
					Thread.yield();
			} catch (Throwable ex) {
			}
		}
	}

	public int getIndex() {
		return this.i;
	}

	public boolean isRunning() {
		return !this.HALT.get();
	}

	public boolean isStopped() {
		return this.HALT.get();
	}

	@Override
	public boolean isBusy() {
		return this.BUSY.get();
	}

	@Override
	public String toString() {
		return "BQDEThreadLP[hash=" + MathUtil.toHex(super.hashCode()) + ",index=" + this.i + ",busy=" + this.BUSY.get() + "]";
	}

	@Override
	public boolean isBatchingThreads() {
		return false;
	}

	@Override
	public void stopThread() {
		this.HALT.set(true);
		super.interrupt();
	}

	@Override
	public BQDEThreadLP autoStart() {
		super.start();
		return this;
	}

	@Override
	public Thread getThread() {
		return this;
	}
}
